package sagroup.dracots;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.Map.Entry;
import java.io.File;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * CostMonitor maintains a log for local node.
 * 
 * @author Huang Xiaodong
 */
public class CostMonitor // extends Monitor
{
	/**
	 * path for log file
	 */
	private String outputPath = "./log/";

	/**
	 * this hashtable[String,CostMonitor] keeps track of the existing
	 * CostMonitors for this host
	 */
	protected static Hashtable CostMonitors = new Hashtable();

	/**
	 * the log information classified by TupleType <type, costInfo> Use HashMap
	 * not Hashtable, because the key could be a null value
	 */
	private HashMap<String, ArrayList<CostInfo>> costInfoLogs;

	/**
	 * the log information classified by TupleType <type, costInfo> Use HashMap
	 * not Hashtable, because the key could be a null value
	 */
	private HashMap<String, ArrayList<CostInfo>> cacheCostInfoLogs;
	
	
	/**
	 * all log information in memory
	 */
	private static ArrayList<CostInfo> logCache;

	/**
	 * name of TupleSpace that owns this monitor
	 */
	private String ownerName;
	
	

	/**
	 * @param ownerName
	 *            the name of TupleSpace that owns this monitor
	 * 
	 * @author Huang Xiaodong
	 */
	private CostMonitor(String ownerName) {
		this.ownerName = ownerName;
		logCache = new ArrayList<CostInfo>();
		costInfoLogs = new HashMap<String, ArrayList<CostInfo>>();
		cacheCostInfoLogs = new HashMap<String, ArrayList<CostInfo>>();
	}
    
	public   HashMap<String, ArrayList<CostInfo>>  GetCacheCostInfoLogs()
	{
		return this.cacheCostInfoLogs;
	}
	/**
	 * @return ownerName
	 * @author Huang Xiaodong
	 */
	public String getOwnerName() {
		return this.ownerName;
	}

	/**
	 * Get CostMonitor of specified TupleSpace
	 * 
	 * @param TSName
	 *            name of TupleSpace that owns this monitor
	 * @return CostMonitor of specified TupleSpace
	 * @author Huang Xiaodong
	 */
	public static CostMonitor getMonitor(String TSName) {
		CostMonitor ret = null;
		if (TSName != null) {
			try {
				ret = (CostMonitor) CostMonitors.get(TSName);
			} catch (ClassCastException e) {
				ret = null;
			}
			if (ret == null) {
				ret = new CostMonitor(TSName);
				CostMonitors.put(TSName, ret);
			}
		}
		return ret;
	}

	/**
	 * @author Huang Xiaodong
	 */
	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();

		for (Entry<String, ArrayList<CostInfo>> e : costInfoLogs.entrySet()) {
			sb.append("type: " + e.getKey() + "\n");
			for (CostInfo ci : e.getValue()) {
				int num = 1;
				sb.append(num++ + " " + ci.toString() + "\n");
			}
		}
		return sb.toString();
	}

	/**
	 * Write the log into an excel workbook. After writing, the CostInfo in
	 * memory will be released.
	 * 
	 * @author Huang Xiaodong
	 */
	@SuppressWarnings("deprecation")
	public String writeLog(String outputPath) {
		// if null, use default outputPath "./log/"
		if (outputPath != null)
			this.outputPath = outputPath;

		// the full outputPath including file name
		String fullPath = null;

		HSSFWorkbook wb = new HSSFWorkbook();
		HSSFSheet sheet = null;
		HSSFRow row = null;

		sheet = wb.createSheet("LocalLog");

		// add header
		row = sheet.createRow(0);

		row.createCell((short) 0).setCellValue("TupleType");
		row.createCell((short) 1).setCellValue("OperationType");
		row.createCell((short) 2).setCellValue("SourceLocation");
		row.createCell((short) 3).setCellValue("TargetLoaction");

		row.createCell((short) 4).setCellValue("LogTime");
		row.createCell((short) 5).setCellValue("TupleSize");
		row.createCell((short) 6).setCellValue("TotalReadTime");
		row.createCell((short) 7).setCellValue("TotalWriteTime");

		row.createCell((short) 8).setCellValue("StartTime");
		row.createCell((short) 9).setCellValue("ProcessTime");
		row.createCell((short) 10).setCellValue("EndTime");

		row.createCell((short) 11).setCellValue("TupleID");

		for (int i = 1; i <= logCache.size(); i++) {
			row = sheet.createRow(i);
			CostInfo info = logCache.get(i - 1);
			row.createCell((short) 0).setCellValue(
					(info.getType() != null) ? info.getType().toString()
							: "NONE");
			row.createCell((short) 1).setCellValue(info.getOperationType());
			row.createCell((short) 2).setCellValue(
					(info.getSourceLocation() != null) ? info
							.getSourceLocation().toString() : "NONE");
			row.createCell((short) 3).setCellValue(
					(info.getTargetLocation() != null) ? info
							.getTargetLocation().toString() : "NONE");

			row.createCell((short) 4).setCellValue(info.getLogTime());
			row.createCell((short) 5).setCellValue(info.getSize());
			row.createCell((short) 6).setCellValue(info.getTotalReadTime());
			row.createCell((short) 7).setCellValue(info.getTotalWriteTime());

			row.createCell((short) 8).setCellValue(info.getStartTime());
			row.createCell((short) 9).setCellValue(info.getProcessTime());
			row.createCell((short) 10).setCellValue(info.getEndTime());

			row.createCell((short) 11).setCellValue(
					(info.getTupleID() != null) ? info.getTupleID().toString()
							: "NONE");

		}
		// write to file
		try {
			File file = new File(this.outputPath);
			if (!file.exists() || !file.isDirectory()) {
				System.out.println("Output path" + this.outputPath
						+ "does not exist. Try to build directory...");
				try {
					file.mkdirs();
					System.out.println("Succeed to build directory.");
				} catch (SecurityException se) {
					System.out.println("Fail to build directory.");
					se.printStackTrace();
				}
			}
			if (file.exists() && file.isDirectory()) {
				fullPath = this.outputPath + "LimeLog"
						+ System.currentTimeMillis() + ".xls";
				FileOutputStream output = new FileOutputStream(fullPath);
				wb.write(output);
				output.close();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return fullPath;
	}

	/**
	 *Insert the incoming costinfo into memory.
	 * 
	 *@param CostInfo
	 *@author Huang Xiaodong
	 */
	private void insertCostInfoLog(CostInfo info) {
		if (info != null) {
			info.setLogTime(System.nanoTime());
			String type = (info.getType() != null) ? info.getType().toString()
					: "NONE";
			ArrayList<CostInfo> costInfoList;
			if (!costInfoLogs.containsKey(type)) {
				costInfoList = new ArrayList<CostInfo>();
				costInfoLogs.put(type, costInfoList);
			} else {
				costInfoList = costInfoLogs.get(type);
			}
			costInfoList.add(info);
            
			
			ArrayList<CostInfo> costInfoList1;
			if (!cacheCostInfoLogs.containsKey(type)) {
				costInfoList1 = new ArrayList<CostInfo>();
				cacheCostInfoLogs.put(type, costInfoList);
			} else {
				costInfoList1 = cacheCostInfoLogs.get(type);
			}
			costInfoList1.add(info);
			
			logCache.add(info);
		}
	}
    /**
     * 
     * @return period cost info logs
     * @author Xing Jiankuan
     */
	
	
	public HashMap<String, ArrayList<CostInfo>> getPeriodLogs()
	{
		return cacheCostInfoLogs;
    }
	
	/**
	 * clear the period cost info logs
	 * 
	 * @author Xing Jiankuan
	 */
	public void clearPeriodLogs()
	{
		cacheCostInfoLogs.clear();
    }
	
	/**
	 * record the given costInfo to log
	 * 
	 * @param info
	 *            CostInfo of operation to log
	 * @author Huang Xiaodong
	 */
	public void recordOperation(CostInfo info) {
		insertCostInfoLog(info);
	}

	/**
	 * Clear the logCache and costInfoLogs of the monitor.
	 * 
	 * @author Huang Xiaodong
	 */
	public void clearLog() {
		logCache.clear();
		costInfoLogs.clear();
	}
}
